#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>

#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"

#define BACKLOG 8

using namespace LogModule;
using namespace ThreadPoolModule;

static const uint16_t gport = 8080;
using handler_t = std::function<std::string (std::string&)>;

class TcpServer
{
    using task_t = std::function<void()>;
    struct ThreadData
    {
        int sockfd;
        TcpServer *self;
    };
public:
    TcpServer(handler_t handler, int port = gport)
      : _handler(handler),
        _port(port), 
        _isrunning(false)
    {
    }

    void InitServer()
    {
        // 1. 创建 Tcp Socket
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // TCP SOCKET
        if(_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket";
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket create success, socked is : " << _listensockfd;  

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));;
        local.sin_family = AF_INET;
        local.sin_port = htons(gport);
        local.sin_addr.s_addr = INADDR_ANY;

        // 2. bind
        int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success, sockfd is : " << _listensockfd;
        
        // 3.cs, tcp 是面向连接的，因此需要 tcp 随时随地等待被连接 
        // tcp 需要将 socket 设置为监听状态
        n = ::listen(_listensockfd, BACKLOG);
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            Die(SOCKET_ERR);
            
        }
        LOG(LogLevel::INFO) << "listen success, sockfd is : " << _listensockfd;
    
    }

    void HandlerRequest(int sockfd) // TCP 同UDP 一样，也全双工通信
    {
        LOG(LogLevel::INFO) << "HandlerRequest, sockfd is : " << sockfd;
        char inbuffer[4096];
        std::string package;
        // 长任务，在线程池中一般是处理短任务的, 因此对应的我们的线程池应该调大点
        while(true)
        {
            memset(inbuffer, 0, sizeof(inbuffer)); // 清空缓冲区

            // 约定：用户发过来的是一个完整命令 string
            ssize_t n = ::recv(sockfd, inbuffer, sizeof(inbuffer) - 1, 0);
            
            if(n > 0)
            {
                inbuffer[n] = 0; // 确保字符串以 null 结尾
                LOG(LogLevel::INFO) << "\n" << inbuffer;
                package += inbuffer; //  报文风格：len\r\n{json}\r\n

                std::string cmd_result = _handler(package);
                if(cmd_result.empty()) continue;

                ::send(sockfd, cmd_result.c_str(), cmd_result.size(), 0);
            }
            else if(n == 0)
            {
                // read 如果读取返回值为 0，表示 client 退出
                LOG(LogLevel::INFO) << "client quit: " << sockfd;
                break;
            }
            else
            {
                // 处理 read 错误
                if (errno == EINTR) {
                    continue; // 信号中断，重试
                }
                LOG(LogLevel::ERROR) << "read error: " << strerror(errno) ;
                break;
            }
        }
        // 关闭套接字
        ::close(sockfd); // fd 泄露问题

    }

    static void *ThreadEntry(void *args)
    {
        pthread_detach(pthread_self()); // 分离
        ThreadData* data = (ThreadData*)args;
        data->self->HandlerRequest(data->sockfd);
        // data 是通过 new 动态分配的内存，需要在不再使用时手动释放
        delete data;
        return nullptr;
    }

    void start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            // 不能直接读取数据
            // 1. 获取新连接
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer); // 这个地方在本地可能没问题，但是到网络的时候可能就有问题！！！
            LOG(LogLevel::DEBUG) << "accept ing ...";
            // 我们要获取 client 的信息：数据（sockfd） + client socket 信息（accept | recvfrom）
            int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);
            if(sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accepet error: " << strerror(errno); 
                continue;
            }

            // 获取连接成功
            LOG(LogLevel::INFO) << "accept success, sockfd is : " << sockfd;

            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "client info : " << addr.Addr();

            // version-3：线程池版本 比较时候处理短任务
            // task_t f = std::bind(&TcpServer::HandlerRequest, this, sockfd); // 构建任务
            // ThreadPool<task_t>::getInstance()->Equeue(f);
            // 我们这里也可以 Lambda 表达式 --> 需要对Equeue那的T &in 的 & 删去
            ThreadPool<task_t>::getInstance()->Equeue([this, sockfd](){
                this->HandlerRequest(sockfd);                                
            });
        }
    }

    void Stop()
    {
        _isrunning = true;
    }

    ~TcpServer()
    {
    }

private:
    int _listensockfd; // 监听 socket
    uint16_t _port;
    bool _isrunning;

    // 处理上层任务的入口
    handler_t _handler;
};